home *** CD-ROM | disk | FTP | other *** search
/ Gold Medal Software 3 / Gold Medal Software - Volume 3 (Gold Medal) (1994).iso / utils1 / hdnfojt.arj / HDINFO.CPP < prev    next >
C/C++ Source or Header  |  1993-11-23  |  6KB  |  185 lines

  1. #include <dos.h>
  2. #include <string.h>
  3. #include <conio.h>
  4. #include <mem.h>
  5. #include "hdinfo.h"
  6.  
  7. unsigned secbuf[2][256];
  8. unsigned char biosbuf[64];
  9.  
  10. int drive0;
  11. int drive1;
  12. long thcap;
  13. unsigned char temp;
  14.  
  15. void readsect( int drive)
  16. // This function reads the drive parameter directly into
  17. // 256 byte buffer.  A 256 byte sector must be read, despite
  18. // the fact that only the first few bytes are actually useful
  19. // (see ideinfo struct)
  20.     {
  21.     int i;
  22.  
  23.     outp(HDC_SDH, 0xA0 + (drive<<4));                // Setup task file parameter
  24.     outp(HDC_COMMAND, HDC_COMMAND_READPAR);        // Issue read parameters command
  25.     while(inp(HDC_STATUS) & HDC_STATUS_BUSY);      // Poll DRQ
  26.     for (i=0; i<256; ++i)                                // Read Sector
  27.         secbuf[drive][i] = inpw(HDC_DATA);
  28.     };
  29.  
  30. void interpret_info( int drive)
  31. // now interpret the data read by the previous function
  32.     {
  33.     int i, k;
  34.     char c;
  35.     char s[80];
  36.     struct ideinfo *id = (struct ideinfo *)secbuf[drive];
  37.  
  38.     thcap = ((long)id->fixcyls * id->heads);
  39.     id->capacity = ((double)thcap * id->sectors) / 2048;
  40.     id->bioscapacity = ((double)id->biosheads * id->biossecs * id->bioscyls)/2048;
  41.  
  42.     // ascii strings read from the drive are read as INTS with the
  43.     // opposite high/low byte ordering than the PC.
  44.     // Therefore we must swap alternate bytes to return
  45.     // to normal intel 80x86 ordering.
  46.  
  47.     // fix serial string
  48.     for(i=0; i < 10; ++i)
  49.         {
  50.         c = id->serial[i*2];
  51.         id->serial[i*2] = id->serial[i*2+1];
  52.         id->serial[i*2+1] = c;
  53.         };
  54.  
  55.     // fix firmware revision string
  56.     for(i=0; i < 4; ++i)
  57.         {
  58.         c = id->firmware[i*2];
  59.         id->firmware[i*2] = id->firmware[i*2+1];
  60.         id->firmware[i*2+1] = c;
  61.         };
  62.  
  63.     // fix model information string
  64.     for(i=0; i < 20; ++i)
  65.         {
  66.         c = id->model[i*2];
  67.         id->model[i*2] = id->model[(i*2)+1];
  68.         id->model[i*2+1] = c;
  69.         };
  70.  
  71.     // for Seagate and Western Digital drives, expand the model
  72.     // data so it is clear who the manufacturer is.  There are
  73.     // probably umpteen more drives where this is necessary, but
  74.     // these are the ones I come across on a day to day basis.
  75.     if( memicmp( id->model, "WDC", 3) == 0)
  76.         {
  77.         strcpy( s, "Western Digital -");
  78.         strcat( s, (char *)id->model+3);
  79.         strncpy( id->model, s, 40);
  80.         };
  81.     if( memicmp( id->model, "st", 2) == 0)
  82.         {
  83.         strcpy( s, "Seagate - ST");
  84.         strcat( s, (char *)id->model+2);
  85.         strncpy( id->model, s, 40);
  86.         };
  87.  
  88.     // if controller type is 4 or above it is unknown
  89.     if( id->contype > 4) id->contype = 4;
  90.  
  91.     // convert the dblword flag into an integer value indicating
  92.     // the number of bits (16 or 32) that can be transfered in a single
  93.     // read/write via the hard drive controller
  94.     ++id->dblword <<= 4;
  95.  
  96.     id->bestcyls = id->fixcyls;
  97.     id->bestheads = id->heads;
  98.     id->bestsecs = id->sectors;
  99.  
  100.     // if the number of physical cylinders is greater than 1024
  101.     // then the drive internally remaps its configuration to suit
  102.     // the PC bios (which only allows a maximum of 1024 cylinders).
  103.     // We therefore need to calculate BIOS settings which are legal
  104.     // (as far as the BIOS is concerned) but which still give us 100%
  105.     // use of the physical drive space.  All drives that I have
  106.     // tested seem to hold the sector/cylinders constant and modify
  107.     // the number of heads on the drive.
  108.     // BIOS uses allows the following maximum values:-
  109.     //        Cylinders = 1024            : 10 bits
  110.     //        Heads = 256                    : 8 bits
  111.     //        Sectors/Cylinder = 64    : 5 bits
  112.     if (id->fixcyls >= 1024)
  113.         {
  114.         for ( i = id->heads; i < 256 ; i++)
  115.             if ( ((thcap % i) == 0) && ((thcap / i) < 1024) )
  116.                 {
  117.                 id->bestcyls = thcap / i;
  118.                 id->bestheads = i;
  119.                 id->bestsecs = id->sectors;
  120.                 break;
  121.                 };
  122.         // if no factors can be found and we still have over 1024 cylinders
  123.         // then truncate the excess - some Maxtor drive do this (which means
  124.         // that you can never use all the space on those models - on a PC)
  125.         if (id->bestcyls >= 1024) id->bestcyls = 1024;
  126.         };
  127.     };
  128.  
  129.  
  130. int check_drive( int drive)
  131.     // Check to see if the drive exists or not.
  132.     // Returns true if the drive is there.
  133.     {
  134.     outp(HDC_SDH, 0xA0 + (drive<<4));                // Setup task file parameter
  135.     if (inp(HDC_STATUS) == 0xFF) return(0);        // if status = 0xff then no disk
  136.     while(inp(HDC_STATUS) & HDC_STATUS_BUSY);      // Poll DRQ and wait if necc.
  137.     outp(HDC_CYLLOW, 0xAA);                      // test even bits in port
  138.     if (inp(HDC_CYLLOW) != 0xAA) return(0);        // if change then no disk
  139.     outp(HDC_CYLLOW, 0x55);                      // test odd bits in port
  140.     if (inp(HDC_CYLLOW) != 0x55) return(0);        // if change then no disk
  141.     if ((inp(HDC_STATUS) & 0x40) == 0) return(0);  // check status changes
  142.     return( 1);
  143.     };
  144.  
  145. void readbios( int drive)
  146. // get the drive information as it is stored for BIOS use
  147.     {
  148.     union REGS regs;
  149.     struct ideinfo *id = (struct ideinfo *)secbuf[drive];
  150.  
  151.     // use BIOS interrupt 0x13 function 8 to get drive details
  152.     regs.h.ah = 0x08;
  153.     regs.h.dl = drive+0x80;         // bit 7 set for hard drives
  154.     int86(0x13, ®s, ®s);
  155.     if (regs.h.dl < (drive+1)) return;
  156.     id->biosheads = regs.h.dh + 1;
  157.     id->biossecs = regs.h.cl & 0x3f;
  158.  
  159.     // for some reason the BIOS int 0x13 funct. 8 does not return
  160.     // the same number as cylinders as the CMOS settings for the
  161.     // drive (it is always 1 or 2 short).  However reading the
  162.     // number of cylinder directly from the drive parameter table
  163.     // gives the correct result (where does BIOS go wrong?).
  164.  
  165.     if (drive == 0) id->bioscyls = **(unsigned int far * far *)(0x41 * 4);
  166.     if (drive == 1) id->bioscyls = **(unsigned int far * far *)(0x46 * 4);
  167.     };
  168.  
  169.  
  170. void readdrives( void)
  171. // This is the main function which calls all the rest.
  172.     {
  173.     outp(HDC_FIXED, 0);                                // Disable drive interrupts
  174.     drive0 = check_drive( DRIVE_0);                // check that drive 0 exists
  175.     drive1 = check_drive( DRIVE_1);                // check that drive 1 exists
  176.     if (drive0) readsect( DRIVE_0);                // if exists read data for drive 0
  177.     if (drive1) readsect( DRIVE_1);                // if exists read data for drive 1
  178.     outp(HDC_FIXED, HDC_FIXED_IRQ);           // Re-enable disk interrupts
  179.     if (drive0) readbios( DRIVE_0);                // Get Bios data for drive 0
  180.     if (drive1) readbios( DRIVE_1);                // Get Bios data for drive 1
  181.  
  182.     if (drive0) interpret_info( DRIVE_0);        // Calculate capacity etc
  183.     if (drive1) interpret_info( DRIVE_1);        // calculate stats for drive 1
  184.     };
  185.